using System;
using System.Collections;
using System.Windows.Forms;
using Microsoft.Xna.Framework.Graphics;
using RebelStar.Engine;
using RebelStar.Engine.GameView;
using RebelStar.Engine.Maps;
using RebelStar.Engine.Players;
using RebelStar.Engine.Sprites;
using RebelStar.Engine.Units;
#if GDI
using RebelStar.Engine.Graphics.GDI;
#else 
using RebelStar.Engine.Graphics.MDX;
#endif

namespace RebelStar.Mapeditor
{
    public partial class EditForm : Form
    {
        GameBase gameBase;
        bool drawMode = false;

        public EditForm()
        {
            InitializeComponent();
            InitializeGraphics();

            this.hScroll.Scroll += this.scroll_Scroll;
            this.vScroll.Scroll += this.scroll_Scroll;
            this.btnBlend.Click += this.btnBlend_Click;
            this.btnUnblend.Click += this.btnUnblend_Click;
            this.btnNextTurn.Click += this.btnNextTurn_Click;
            this.btnFireLeft.Click += this.btnFire_Click;
            this.btnFireRight.Click += this.btnFire_Click;
            this.cbEnableFog.CheckedChanged += cbEnableFog_CheckedChanged;
            this.trackZoom.ValueChanged += trackZoom_ValueChanged;
            
            this.KeyPreview = true;
            this.KeyUp += EditForm_KeyUp;
            this.Shown += EditForm_Shown;

            this.panel1.MouseMove += panel1_MouseMove;
            this.panel1.MouseDown += panel1_MouseDown;
            this.panel1.MouseUp += panel1_MouseUp;
            this.cmbPlayers.SelectedIndexChanged += cmbPlayers_SelectedIndexChanged;

//            trackZoom.Value = 6;
            btnFireLeft.Enabled = false;
            btnFireRight.Enabled = false;
        }

        public void InitializeGraphics()
        {
            try
            {
                this.panel1.Initialize();

#if GDI
                gameBase = new GameBase(new GDIGraphicsDevice(this.panel1));
#else 
                gameBase = new GameBase(new MDXGraphicsDevice(this.panel1));
#endif
                gameBase.Initialize();

                gameBase.LoadMap();
                gameBase.AddPlayer("Player 1");
                gameBase.AddPlayer("Player 2");

                const float spriteScale = 0.75f;

                addSpriteTab("Terrains", gameBase.Map.TerrainSprites, terrainSprite_DoubleClick, spriteScale, 3);
                addSpriteTab("Structures", gameBase.Map.StructureSprites, structureSprite_DoubleClick, spriteScale, 3);
                addSpriteTab("Units", gameBase.Map.UnitSprites, unitSprite_DoubleClick, spriteScale, 3);

                hScroll.Maximum = gameBase.MapWidth;
                vScroll.Maximum = gameBase.MapHeight;
                foreach (Player player in gameBase.Players)
                    cmbPlayers.Items.Add(player);                    
                cmbPlayers.SelectedIndex = 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void updateCurrentUnit()
        {
            updateUnitInfo(gameBase.CurrentPlayer.SelectedUnit);
        }
        void updateUnitInfo(Unit unit)
        {
            panUnit.SetSprite(unit != null ? unit.Sprite : null, unit != null ? Unit.STAY_STATE : 0);
            lblAPVal.Text = unit != null ? unit.CurrentAP.ToString() : "0";
            lblHPVal.Text = unit != null ? unit.HP.ToString() : "0";
            if (unit == null || unit.Slots.Count == 0 || !unit.Slots[0].IsAvailable)
            {
                lblSlot1.Text = unit == null || unit.Slots.Count == 0 ? "Slot 1:" : unit.Slots[0].Name;
                lblLNameVal.Text = "None";
                lblLPowVal.Text = "0";
                lblLAccVal.Text = "0";
                lblLSnapVal.Text = "0";
                lblLAimedVal.Text = "0";
                btnFireLeft.Enabled = false;
            } 
            else
            {
                lblSlot1.Text = unit.Slots[0].Name;
                lblLNameVal.Text = unit.Slots[0].Weapon.Name;
                lblLPowVal.Text = unit.Slots[0].Weapon.Power.ToString();
                lblLAccVal.Text = unit.Slots[0].Weapon.Accuracy.ToString();
                lblLSnapVal.Text = unit.Slots[0].Weapon.Actions[0].AP.ToString();
                lblLAimedVal.Text = unit.Slots[0].Weapon.Actions[1].AP.ToString();
                btnFireLeft.Enabled = true;
            }
            if (unit == null || unit.Slots.Count==1 || !unit.Slots[1].IsAvailable)
            {
                lblSlot2.Text = unit == null || unit.Slots.Count == 1 ? "Slot 2:" : unit.Slots[1].Name;
                lblRNameVal.Text = "None";
                lblRPowVal.Text = "0";
                lblRAccVal.Text = "0";
                lblRSnapVal.Text = "0";
                lblRAimedVal.Text = "0";
                btnFireRight.Enabled = false;
            } 
            else
            {
                lblSlot2.Text = unit.Slots[1].Name;
                lblRNameVal.Text = unit.Slots[1].Weapon.Name;
                lblRPowVal.Text = unit.Slots[1].Weapon.Power.ToString();
                lblRAccVal.Text = unit.Slots[1].Weapon.Accuracy.ToString();
                lblRSnapVal.Text = unit.Slots[1].Weapon.Actions[0].AP.ToString();
                lblRAimedVal.Text = unit.Slots[1].Weapon.Actions[1].AP.ToString();
                btnFireRight.Enabled = true;
            }
        }
        void addSpriteTab(string caption, IEnumerable sprites, EventHandler handler, float scale, int colCount)
        {
            TabPage tp = new TabPage(caption);
            tabControl1.TabPages.Add(tp);
            tp.AutoScroll = true;
            int row = 0;
            int col = 0;
            foreach (SpriteBase sprite in sprites)
            {
                for (int i = 0; i < sprite.StatesCount; i++)
                {
                    GameSpritePanel spritePanel = new GameSpritePanel(scale);
                    spritePanel.Selectable = true;
                    spritePanel.SetSprite(sprite, i);
                    spritePanel.Left = 4 + col * (spritePanel.Width + 4);
                    spritePanel.Top = 4 + (row / colCount) * (spritePanel.Height + 4);
                    spritePanel.DoubleClick += handler;
                    spritePanel.Enter += spritePanel_Enter;
                    tp.Controls.Add(spritePanel);
                    row++;
                    col++;
                    if (col % colCount == 0) col = 0;
                }
            }
        }

        void btnBlend_Click(object sender, EventArgs e)
        {
            this.gameBase.BlendMap(Color.Gray);
        }
        void btnUnblend_Click(object sender, EventArgs e)
        {
            this.gameBase.BlendMap(Color.White);
        }
        void cmbPlayers_SelectedIndexChanged(object sender, EventArgs e)
        {
            gameBase.CurrentPlayer = (Player)cmbPlayers.SelectedItem;
            gameBase.ReDraw();
            updateCurrentUnit();
        }
        void btnNextTurn_Click(object sender, EventArgs e)
        {
            gameBase.NextTurn();
            if (cmbPlayers.SelectedItem != gameBase.CurrentPlayer)
                cmbPlayers.SelectedItem = gameBase.CurrentPlayer;
            else
            {
                gameBase.ReDraw();
                updateCurrentUnit();
            }
        }        
        void btnRefreshFog_Click(object sender, EventArgs e)
        {
            gameBase.CurrentPlayer.RefreshFog();
            gameBase.ReDraw();
        }
        void cbEnableFog_CheckedChanged(object sender, EventArgs e)
        {
            gameBase.EnableFog = cbEnableFog.Checked;
        }
        void btnFire_Click(object sender, EventArgs e)
        {
            if (gameBase.CurrentPlayer == null || gameBase.CurrentPlayer.SelectedUnit == null) return;

            gameBase.SetFireMode(gameBase.CurrentPlayer.SelectedUnit,
                                 sender == btnFireLeft
                                     ? gameBase.CurrentPlayer.SelectedUnit.Slots[0].Weapon
                                     : gameBase.CurrentPlayer.SelectedUnit.Slots[1].Weapon, 
                                 sender == btnFireLeft
                                     ? gameBase.CurrentPlayer.SelectedUnit.Slots[0].Weapon.Actions[0]
                                     : gameBase.CurrentPlayer.SelectedUnit.Slots[1].Weapon.Actions[1]);
            gameBase.ReDraw();
        }
        void scroll_Scroll(object sender, ScrollEventArgs e)
        {
            gameBase.Scroll(
                e.ScrollOrientation == ScrollOrientation.HorizontalScroll ? e.NewValue - e.OldValue : 0,
                e.ScrollOrientation == ScrollOrientation.VerticalScroll ? e.NewValue - e.OldValue : 0);
        }
        void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            gameBase.SetCursor(e.X, e.Y);
            label1.Text = string.Format(@"Mouse: X={0}; Y={1}; Cursor: X={2}; Y={3}", e.X, e.Y, gameBase.Cursor.X, gameBase.Cursor.Y);
            if (drawMode)
            {
                if (selectedSpritePanel.Sprite is StructureSprite)
                    gameBase.AddStructure(gameBase.CursorEntry, selectedSpritePanel.Sprite as StructureSprite,
                                                      selectedSpritePanel.SpriteState);
                else if (selectedSpritePanel.Sprite is TerrainSprite)
                    gameBase.ChangeTerrain(gameBase.CursorEntry, selectedSpritePanel.Sprite as TerrainSprite,
                                                       selectedSpritePanel.SpriteState);
            }
        }
        void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Left:
                gameBase.StartSelection(gameBase.Cursor.X, gameBase.Cursor.Y);
                    break;
                case MouseButtons.Middle:
                    if (selectedSpritePanel.Sprite != null)
                        drawMode = true;
                    break;
                case MouseButtons.Right:
                case MouseButtons.XButton1:
                case MouseButtons.XButton2:
                case MouseButtons.None:
                default:
                    break;
            }
        }        
        void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Left:
                    gameBase.EndSelection(gameBase.Cursor.X, gameBase.Cursor.Y);
                    break;
                case MouseButtons.Middle:
                    drawMode = false;
                    break;
                case MouseButtons.Right:
                case MouseButtons.XButton1:
                case MouseButtons.XButton2:
                    gameBase.ResetSelection();
                    break;
                case MouseButtons.None:
                default:
                    break;
            }
            updateCurrentUnit();
        }
        void EditForm_KeyUp(object sender, KeyEventArgs e)
        {
            e.Handled = true;
            gameBase.KeyPress(e.KeyCode);
            gameBase.ReDraw();
            updateCurrentUnit();
        }
        void EditForm_Shown(object sender, EventArgs e)
        {
            gameBase.ReDraw();
        }
        void trackZoom_ValueChanged(object sender, EventArgs e)
        {
            gameBase.SetScale(trackZoom.Value / (float)trackZoom.Maximum);
            hScroll.Maximum = gameBase.MapWidth-gameBase.MapVisibleRect.Width;
            vScroll.Maximum = gameBase.MapHeight-gameBase.MapVisibleRect.Height;
            if (hScroll.Maximum < 0) hScroll.Value = hScroll.Maximum = 0;
            if (vScroll.Maximum < 0) vScroll.Value = vScroll.Maximum = 0;
        }
        void terrainSprite_DoubleClick(object sender, EventArgs e)
        {
            GameSpritePanel sp = sender as GameSpritePanel;
            foreach (MapEntry entry in gameBase.Selection)
                gameBase.ChangeTerrain(entry, sp.Sprite as TerrainSprite, sp.SpriteState);
            gameBase.ReDraw();
        }
        void structureSprite_DoubleClick(object sender, EventArgs e)
        {
            GameSpritePanel sp = sender as GameSpritePanel;
            foreach (MapEntry entry in gameBase.Selection)
                gameBase.AddStructure(entry, sp.Sprite as StructureSprite, sp.SpriteState);
            gameBase.ReDraw();
        }
        void unitSprite_DoubleClick(object sender, EventArgs e)
        {
            GameSpritePanel sp = sender as GameSpritePanel;
            foreach (MapEntry entry in gameBase.Selection)
                gameBase.CurrentPlayer.Units.Add(new Unit(sp.Sprite as UnitSprite, gameBase.Map.GetPosition(entry)));
            gameBase.ReDraw();
        }
        void spritePanel_Enter(object sender, EventArgs e)
        {
            GameSpritePanel sp = sender as GameSpritePanel;
            if (sp != null) selectedSpritePanel.SetSprite(sp.Sprite, sp.SpriteState);
        }
    }
}